#pragma once
#include "vk_utils.h"
#include "vk_device_context.h"

namespace vkrender
{
    struct PipelineConfigInfo 
    {
        PipelineConfigInfo() = default;
        PipelineConfigInfo(const PipelineConfigInfo&) = delete;
        PipelineConfigInfo& operator=(const PipelineConfigInfo&) = delete;

        // VkViewport viewport;
        // VkRect2D scissor;
        VkPipelineViewportStateCreateInfo viewportInfo;
        VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo;
        VkPipelineRasterizationStateCreateInfo rasterizationInfo;
        VkPipelineMultisampleStateCreateInfo multisampleInfo;
        VkPipelineColorBlendAttachmentState colorBlendAttachment;
        VkPipelineColorBlendStateCreateInfo colorBlendInfo;
        VkPipelineDepthStencilStateCreateInfo depthStencilInfo;
        std::vector<VkDynamicState> dynamicStatesEnabled;
        VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo;

        VkPipelineLayout pipelineLayout = nullptr;
        VkRenderPass renderPass = nullptr;
        uint32_t subpass = 0;
    };

    class VulkanGraphicsPipeline 
    {
    public:
        VulkanGraphicsPipeline(
            std::shared_ptr<VulkanDeviceContext>& context,
            const std::string& vertFilepath,
            const std::string& fragFilepath,
            const std::vector<VkVertexInputBindingDescription>& bindingDescriptions,
            const std::vector<VkVertexInputAttributeDescription> attributeDescriptions,
            const PipelineConfigInfo& configInfo);
        ~VulkanGraphicsPipeline();

        void bind(VkCommandBuffer commandBuffer);

        static void defaultPipelineConfigInfo(PipelineConfigInfo& configInfo);

    private:
        static std::vector<char> readFile(const std::string& filepath);

        void createGraphicsPipeline(
            const std::string& vertFilepath,
            const std::string& fragFilepath,
            const std::vector<VkVertexInputBindingDescription>& bindingDescriptions,
            const std::vector<VkVertexInputAttributeDescription> attributeDescriptions,
            const PipelineConfigInfo& configInfo);

        void createShaderModule(const std::vector<char>& code, VkShaderModule* shaderModule);

        VkDevice device;
        VkPipeline graphicsPipeline;
        VkShaderModule vertShaderModule;
        VkShaderModule fragShaderModule;
    };
}

